package com.gitee.l0km.jsonvisitor;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.file.Path;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

import com.google.common.base.Throwables;
import com.gitee.l0km.jsonvisitor.listener.ParserErrorListener;
import com.gitee.l0km.jsonvisitor.parser.JSONLexer;
import com.gitee.l0km.jsonvisitor.parser.JSONParser;
import com.gitee.l0km.jsonvisitor.parser.JSONVisitor;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static org.antlr.v4.runtime.CharStreams.fromString;
import static org.antlr.v4.runtime.CharStreams.fromStream;
import static org.antlr.v4.runtime.CharStreams.fromPath;
import static org.antlr.v4.runtime.CharStreams.fromReader;
import static org.antlr.v4.runtime.CharStreams.fromFileName;
import static com.gitee.l0km.jsonvisitor.utils.CharStreamSupport.asCharStream;

/**
 * JSON语句解析工具类
 * @author guyadong
 */
public class JsonVisitorParser {

	public static final JsonVisitorParser PARSER = new JsonVisitorParser();
	protected JsonVisitorParser() {
	}
	/**
	 * 解析输入的字符流，返回解析对象
	 * @param input 输入为{@code null}返回{@code null}
	 * @param method 要调用的{@link JSONParser}定义的解析方法名,如{@code 'statements','defineScreen'},方法名无效则抛出异常
	 * @param jsonVisitor 
	 */
	public <T> T parse(CharStream input,String method, JSONVisitor<T> jsonVisitor) {
		if(null == input || isNullOrEmpty(method) || null == jsonVisitor) {
			return null;
		}
		try {
			JSONParser parser = createAntlrParser(input);
			ParseTree tree = (ParseTree) parser.getClass().getMethod(method).invoke(parser);
			return (T) jsonVisitor.visit(tree);
		} catch (IllegalAccessException | NoSuchMethodException | SecurityException e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}catch (InvocationTargetException e) {
			Throwables.throwIfUnchecked(e.getTargetException());
			throw new RuntimeException(e.getTargetException());
		}
	}
	/**
	 * @see #parse(CharStream, String, JSONVisitor)
	 */
	public <T> Object parse(Path path,String method, JSONVisitor<T> jsonVisitor) throws IOException {
		return null == path ? null : parse(fromPath(path),method, jsonVisitor);
	}
	/**
	 * @see #parse(CharStream, String, JSONVisitor)
	 */
	public <T>Object parse(File file,String method, JSONVisitor<T> jsonVisitor) throws IOException {
		return null == file ? null : parse(file.toPath(),method,jsonVisitor);
	}
	/**
	 * @see #parse(CharStream, String, JSONVisitor)
	 */
	public <T> Object parse(InputStream inputStream,String method, JSONVisitor<T> jsonVisitor) throws IOException {
		return null == inputStream ? null : parse(fromStream(inputStream),method, jsonVisitor);
	}
	/**
	 * @see #parse(CharStream, String, JSONVisitor)
	 */
	public <T> Object parse(URL url,String method, JSONVisitor<T> jsonVisitor) throws IOException {
		if(null == url) {
			return null;
		}
		try(InputStream is = url.openStream()){
			return parse(is,method,jsonVisitor);
		}
	}
	/**
	 * @see #parse(CharStream, String, JSONVisitor)
	 */
	public <T> Object parse(Reader reader,String method, JSONVisitor<T> jsonVisitor) throws IOException {
		return null == reader ? null : parse(fromReader(reader),method, jsonVisitor);
	}
	/**
	 * @see #parse(CharStream, String, JSONVisitor)
	 */
	public <T> Object parseFile(String fileName,String method, JSONVisitor<T> jsonVisitor) throws IOException {
		return isNullOrEmpty(fileName) ? null : parse(fromFileName(fileName),method, jsonVisitor);
	}
	/**
	 * 解析输入的字符串，返回解析对象
	 * @param text
	 * @param method 要调用的{@link JSONParser}定义的解析方法名,如{@code 'statements','defineScreen'},方法名无效则抛出异常
	 * @param jsonVisitor
	 * @see #parse(CharStream, String, JSONVisitor)
	 */
	public <T> Object parse(String text,String method, JSONVisitor<T> jsonVisitor) {
		return isNullOrEmpty(text) ? null : parse(fromString(text),method, jsonVisitor);
	}
	/**
	 * 解析输入的字符流，返回解析对象
	 * @param text 为{@code null}或空返回{@code null}
	 * @param jsonVisitor
	 * @param method 要调用的{@link JSONParser}定义的解析方法名,如{@code 'statements','defineScreen'},方法名无效则抛出异常
	 * @param others 同method参数，允许提供多个方法名尝试
	 */
	public <T> T parse(String text, JSONVisitor<T> jsonVisitor,String method,String... others) {
		if(isNullOrEmpty(text)) {
			return null;
		}
		try {
			return parse(fromString(text),method, jsonVisitor);
		} catch (Exception e) {
			if(null != others) {
				for(String m:others) {
					try {
						if(!isNullOrEmpty(m)) {
							return parse(fromString(text), m, jsonVisitor);
						}
					} catch (Exception e2) {
						// DO NOTHING
					}
				}
			}
			throw e ;
		}
	}
//	public Object  pairVisit(CharStream input){
//		return parse(input, "json", new PairVisitor());
//	}
//	public Object  pairVisit(Path path) throws IOException{
//		return null == path ? null : pairVisit(fromPath(path));
//	}
//	public Object  pairVisit(File file) throws IOException{
//		return null == file ? null : pairVisit(file.toPath());
//	}
//	public Object  pairVisit(InputStream inputStream) throws IOException{
//		return null == inputStream ? null : pairVisit(fromStream(inputStream));
//	}
//	public Object  pairVisit(URL url) throws IOException{
//		if(null == url) {
//			return null;
//		}
//		try(InputStream is = url.openStream()){
//			return pairVisit(is);
//		}
//	}
//	public Object  pairVisit(Reader reader) throws IOException{
//		return null == reader ? null : pairVisit(fromReader(reader));
//	}
//	public Object  pairVisit(String text) throws IOException{
//		return Strings.isNullOrEmpty(text) ? null : pairVisit(fromString(text));
//	}
	public Object  pairVisit(Object src, String key, int ruleIndex){
		return parse(asCharStream(src), "json", new PairVisitor(key,ruleIndex));
	}
	public Object  pairVisit(Object src, String key){
		return pairVisit(src,key,-1);
	}
	/**
	 * 创建ANTLR4生成的解析器对象{@link JSONParser}
	 * @param text 待解析字符串
	 */
	public static JSONParser createAntlrParser(String text) {
		CharStream input = fromString(checkNotNull(text,"text is null"));
		return createAntlrParser(input);
	}
	/**
	 * 创建ANTLR4生成的解析器对象{@link JSONParser}
	 * @param input 待解析的字符流对象
	 */
	public static JSONParser createAntlrParser(CharStream input) {
		if(null == input) {
			return null;
		}
		JSONLexer lexer = new JSONLexer(checkNotNull(input,"input is null"));
		CommonTokenStream tokens = new CommonTokenStream(lexer);
		JSONParser parser = new JSONParser(tokens);
		parser.removeErrorListeners();
		parser.addErrorListener(ParserErrorListener.INSTANCE);
		return parser;
	}
}
